#include "screen.h"

#include "math.h"
#include "usart.h"
#include "coil.h"

screen_set_param screen_set_param_t = { 0 }; // 参数结构体

int g_RawDataBuf[BUFFER_SIZE] = { 0 }; // 原始数据缓冲区（按接收顺序）
int g_SortedDataBuf[BUFFER_SIZE] = { 0 }; // 排序后的数据缓冲区
uint16_t g_Buf_Count = 0; // 实际数据数量


/**
 * @brief 屏幕显示数据初始化
 * @note 发送测试次数和模式的初始参数到屏幕
 */
void ScreenInit(void)
{
	// 根据初始参数往屏幕发送数据
	uint8_t SendData[] = {PROTOCOL_HEADER1, PROTOCOL_HEADER2, FRAME_LEN_SHORT, PROTOCOL_CMD_WRITE, 0x00, TESTTIMES_ADDR, 0x00, 0x00};
	uint8_t SendData2[] = {PROTOCOL_HEADER1, PROTOCOL_HEADER2, FRAME_LEN_SHORT, PROTOCOL_CMD_WRITE, 0x00, MODE, 0x00, 0x00};
	uint8_t SendData3[] = {PROTOCOL_HEADER1, PROTOCOL_HEADER2, FRAME_LEN_SHORT, PROTOCOL_CMD_WRITE, 0x00, TEXTTIME, 0x00, 0x00};
	uint8_t SendData4[] = {PROTOCOL_HEADER1, PROTOCOL_HEADER2, FRAME_LEN_SHORT, PROTOCOL_CMD_WRITE, 0x00, MEMBRANE, 0x00, 0x00};
	// 4字节数据，高位在前
	SendData[6] = (screen_set_param_t.test_times_param >> 8) & 0xff;
	SendData[7] = screen_set_param_t.test_times_param & 0xff;
	SendData2[6] = (screen_set_param_t.test_gauge_mode >> 8) & 0xff;
	SendData2[7] = screen_set_param_t.test_gauge_mode & 0xff;
	SendData3[6] = (screen_set_param_t.test_time >> 8) & 0xff;
	SendData3[7] = screen_set_param_t.test_time & 0xff;
	SendData4[6] = (screen_set_param_t.transfer_membrane >> 8) & 0xff;
	SendData4[7] = screen_set_param_t.transfer_membrane & 0xff;
	// 将模式和次数发送到屏幕初始值
	HAL_UART_Transmit(&huart5, SendData, sizeof(SendData), 0xff);
	HAL_UART_Transmit(&huart5, SendData2, sizeof(SendData2), 0xff);
	HAL_UART_Transmit(&huart5, SendData3, sizeof(SendData3), 0xff);
	HAL_UART_Transmit(&huart5, SendData4, sizeof(SendData4), 0xff);
}

/**
 * @brief 连接上位机，发送实时测试次数和模式
 * @note 模式值+1是因为上位机协议的定义与屏幕显示值定义偏移1
 */
void LinkStart(void)
{
	SoftSendData(SOFT_TIMES_ADDR, screen_set_param_t.test_times_param);
	SoftSendData(SOFT_MODE_ADDR, (screen_set_param_t.test_gauge_mode + 1));
}

/**
 * @brief 将重新设置的模式和实验次数发送到屏幕和软件
 */
void PatternTimesSwitching(void)
{
	ScreenInit();
	LinkStart();
}
/**
 * @brief 发送所有测量参数到屏幕
 */
void ScreenSend(void)
{
	ScreenSendData(DATA_ADDR, screen_set_param_t.test_gauge_param);
	ScreenSendData(MAX_ADDR, screen_set_param_t.max_gauge_param);
	ScreenSendData(MIN_ADDR, screen_set_param_t.min_gauge_param);
	ScreenSendData(MEAN_ADDR, screen_set_param_t.mean_gauge_param);
	ScreenSendData(STD_ADDR, screen_set_param_t.std_gauge_param * 0.01);
	ScreenSendData(NUM_ADDR, screen_set_param_t.num_gauge_param);
}

/**
 * @brief 发送所有测量参数到上位机
 */
void SoftSend(void)
{
	SoftSendData(SOFT_DATA_ADDR, screen_set_param_t.test_gauge_param);
	SoftSendData(SOFT_MAX_ADDR, screen_set_param_t.max_gauge_param);
	SoftSendData(SOFT_MIN_ADDR, screen_set_param_t.min_gauge_param);
	SoftSendData(SOFT_MEAN_ADDR, screen_set_param_t.mean_gauge_param);
	SoftSendData(SOFT_STD_ADDR, screen_set_param_t.std_gauge_param * 0.01);
	SoftSendData(SOFT_NUM_ADDR, screen_set_param_t.num_gauge_param);
}

/********** 主要功能函数**********/
/**
 * @brief 单次获取测量数据并处理
 * @note 从定时器获取脉冲数据，存入缓冲区并更新计算结果
 */
void RecFromOnce(uint8_t mode)
{
	// 通气，传感器头下压
	DRV8870_4_Run(1);
	HAL_Delay(screen_set_param_t.test_time * 50);
	// 获取放大器当前值
	int value = GetSensorValue();
	HAL_Delay(screen_set_param_t.test_time * 50);
	// 抬起传感器头
	DRV8870_4_Run(0);
	// 延时，避免传感器头还没抬起电机就运行
	HAL_Delay(500);
	// 关闭继电器,并控制电机转膜
	if(mode == 0) {
		Transfer_Membrane(screen_set_param_t.transfer_membrane);
	}
	// 延时，避免电机还在转膜传感器头就压下
	HAL_Delay(2000);
	// 调试输出
	printf("放大器当前值：%d\r\n", value);

	// 存储测量值到原始数据缓冲区
	AddToBuffer(&value, 1);

	// 更新显示和计算结果
	// 更新查询页显示（使用非排序原始数据）
	ScreenSendQuery();
	// 计算统计参数
	ParameterCalculation();
	// 测试次数递增
	screen_set_param_t.num_gauge_param++;
	// 发送到屏幕
	ScreenSend();
	// 发送到上位机
	SoftSend();
	printf("标准差：%d\r\n",screen_set_param_t.std_gauge_param);
}

/**
 * @brief 运行测试流程（自动/手动模式）
 * @note 自动模式：按设定次数循环测试；手动模式：单次测试
 */
void Run(void)
{
	if(screen_set_param_t.num_gauge_param == screen_set_param_t.test_times_param) {
		ScreenSendClear();
	}
	// 自动模式
	if(screen_set_param_t.test_gauge_mode == 0) {
		for(int i = screen_set_param_t.num_gauge_param; i < screen_set_param_t.test_times_param; i++) {
			if(stop_flag == 1) {
				stop_flag = 0;
				return;
			}
 			HAL_Delay(100);
			RecFromOnce(screen_set_param_t.test_gauge_mode);
		}
	} else if(screen_set_param_t.test_gauge_mode == 1){ // 手动模式
		HAL_Delay(100);
		RecFromOnce(screen_set_param_t.test_gauge_mode);
	} else {
		printf("测试模式选择错误！\r\n");
	}
}

/**
 * @brief 发送缓冲区数据到调试串口
 */
void SendDebug(void)
{
	// 打印原始数据
	for(int i = 0; i < g_Buf_Count; i++) {
		printf("g_RawDataBuf[%d] = %d\r\n", i, g_RawDataBuf[i]);
	}
	// 打印统计参数
	printf("最大值：%d\r\n", screen_set_param_t.max_gauge_param);
	printf("最小值：%d\r\n", screen_set_param_t.min_gauge_param);
	printf("平均值：%d\r\n", screen_set_param_t.mean_gauge_param);
	printf("标准差：%d\r\n", screen_set_param_t.std_gauge_param);
}

/**
 * @brief 清空所有参数和缓冲区
 * @note 重置结构体、缓冲区并更新屏幕和上位机显示
 */
void ScreenSendClear(void)
{
    // 先保存需要保留的字段值
    uint8_t saved_mode = screen_set_param_t.test_gauge_mode;
    uint8_t saved_total_times = screen_set_param_t.test_times_param;
    uint8_t saved_test_time = screen_set_param_t.test_time;
    uint8_t saved_transfer_membrane = screen_set_param_t.transfer_membrane;
	// 重置参数结构体
	memset(&screen_set_param_t, 0, sizeof(screen_set_param_t));
    // 恢复需要保留的字段值
    screen_set_param_t.test_gauge_mode = saved_mode;
    screen_set_param_t.test_times_param = saved_total_times;
    screen_set_param_t.test_time = saved_test_time;
    screen_set_param_t.transfer_membrane = saved_transfer_membrane;
    // 清空缓冲区
    memset(g_RawDataBuf, 0, sizeof(g_RawDataBuf));
    memset(g_SortedDataBuf, 0, sizeof(g_SortedDataBuf));
    g_Buf_Count = 0;
	// 清空查询页
	uint16_t currentAddr = QUERY_START_ADDR;
	for(int i = 0; i < QUERY_NUM; i++) {
		ScreenSendData(currentAddr, 0);
		currentAddr += QUERY_ADDR_STEP;
		HAL_Delay(1);
	}
    // 更新显示
    ScreenSend();
    SoftSend();
}
/**
 * @brief 添加新数据到原始数据缓冲区
 * @param newData 新数据指针
 * @param newCount 新数据数量
 */
void AddToBuffer(int* newData, uint8_t newCount)
{
    // 确保新数据量不超过缓冲区大小
    if (newCount > BUFFER_SIZE) {
        newData += (newCount - BUFFER_SIZE);  // 只取最后BUFFER_SIZE个数据
        newCount = BUFFER_SIZE;
    }

    // 计算需要保留的旧数据数量
    uint8_t keepCount = (g_Buf_Count < BUFFER_SIZE - newCount) ? g_Buf_Count : BUFFER_SIZE - newCount;
    // 将旧数据向后移动，为新数据腾出空间
    memmove(g_SortedDataBuf + newCount, g_SortedDataBuf, keepCount * sizeof(uint32_t));
    memmove(g_RawDataBuf + newCount, g_RawDataBuf, keepCount * sizeof(uint32_t));
    // 将新数据添加到缓冲区头部
    memcpy(g_SortedDataBuf, newData, newCount * sizeof(uint32_t));
    memcpy(g_RawDataBuf, newData, newCount * sizeof(uint32_t));
    // 更新当前缓冲区中的数据数量
    g_Buf_Count = newCount + keepCount;

    // 缓冲区第一位写为测试当前数据
    screen_set_param_t.test_gauge_param = g_RawDataBuf[0];
}

// 往查询界面写入测试数据
void ScreenSendQuery(void)
{
	uint8_t result = 0;
	int dataCount = (0x9A - 0x30) / 2 + 1;
	uint16_t currentAddr = 0x30;

	// 确保不发送超出缓冲区大小的数据
	int sendCount = (dataCount > g_Buf_Count) ? g_Buf_Count : dataCount;

	for(int i = 0; i < sendCount; i++) {
		result = ScreenSendData(currentAddr, g_RawDataBuf[i]);
		if (result != HAL_OK) {
			printf("Failed to send data to address 0x%04X\r\n", currentAddr);
			// 出错终止循环
			 break; // 在第一个错误时停止
		}
		currentAddr += 2;
	}
}

// 通用发送函数：向指定UART发送数据（addr：地址，data：数据，huart：UART句柄）
uint8_t CommonSendData(UART_HandleTypeDef *huart, uint16_t addr, int data)
{
	int SendResult = 0;
	uint8_t sendData[] = {PROTOCOL_HEADER1, PROTOCOL_HEADER2, FRAME_LEN_LONG, PROTOCOL_CMD_WRITE, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00};
	// 填入地址（2字节，高位在前）
	sendData[4] = (addr >> 8) & 0xff;
	sendData[5] = addr & 0xff;
	// 填入数据（4字节，高位在前）
	sendData[6] = (data >> 24) & 0xff;
	sendData[7] = (data >> 16) & 0xff;
	sendData[8] = (data >> 8) & 0xff;
	sendData[9] = data & 0xff;
	// 发送数据
	SendResult = HAL_UART_Transmit(huart, sendData, sizeof(sendData), 0xff);
	if (SendResult != 0) {
		return HAL_ERROR;
	}
	return HAL_OK;
}

// 往屏幕指定的变量地址addr发送数据data
uint8_t ScreenSendData(uint16_t addr, int data)
{
	return CommonSendData(&huart5, addr, data); // 屏幕用huart5
}

// 往上位机软件发数据
uint8_t SoftSendData(uint16_t addr, int data)
{
	return CommonSendData(&huart6, addr, data); // 上位机用huart6
}

// 参数计算，根据获取到的测试值计算出最大最小平均值和标准差
uint8_t ParameterCalculation(void)
{
    int TempAdjust = 0;
    int TempData = 0;
    int i = 0;
    int j = 0;

    //处理无样本情况
    if (g_Buf_Count == 0) {
    	screen_set_param_t.mean_gauge_param = 0;
    	screen_set_param_t.max_gauge_param = 0;
    	screen_set_param_t.min_gauge_param = 0;
    	screen_set_param_t.std_gauge_param = 0;
    	return HAL_OK;
    }

    //处理样本量只有一个的情况
    if (g_Buf_Count == 1) {
		screen_set_param_t.mean_gauge_param = g_SortedDataBuf[0];
		screen_set_param_t.max_gauge_param = g_SortedDataBuf[0];
		screen_set_param_t.min_gauge_param = g_SortedDataBuf[0];
		screen_set_param_t.std_gauge_param = 0;
		return HAL_OK;
    }

	//排序
    for (i = 0; i < g_Buf_Count - 1; i++) {
		for (j = 0; j < g_Buf_Count - i - 1; j++) {
			if (g_SortedDataBuf[j] < g_SortedDataBuf[j + 1]) {
				TempData = g_SortedDataBuf[j];
				g_SortedDataBuf[j] = g_SortedDataBuf[j + 1];
				g_SortedDataBuf[j + 1] = TempData;
			}
		}
	}
	screen_set_param_t.max_gauge_param = g_SortedDataBuf[0];
	screen_set_param_t.min_gauge_param = g_SortedDataBuf[g_Buf_Count - 1];
	//累加总和
	for (i = 0; i < g_Buf_Count; i++) {
		TempAdjust += g_SortedDataBuf[i];
	}
	//计算平均值
	screen_set_param_t.mean_gauge_param = TempAdjust / g_Buf_Count;
	//先置0
	float std = 0;
	//计算标准差
	for (i = 0; i < g_Buf_Count; i++) {
		std += (g_RawDataBuf[i] - screen_set_param_t.mean_gauge_param) * (g_RawDataBuf[i] - screen_set_param_t.mean_gauge_param);
	}
	std = std / (g_Buf_Count - 1);
	screen_set_param_t.std_gauge_param = sqrt(std);

    return HAL_OK;
}
